package controller

import (
	"RocFamilySystem/internal/service"
	"RocFamilySystem/models"
	"RocFamilySystem/models/dto"
	"RocFamilySystem/pkg/constant"
	"RocFamilySystem/tools/bcrypt"
	"RocFamilySystem/tools/container"
	"RocFamilySystem/tools/jwt"
	"RocFamilySystem/tools/verifyCode"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"net/http"
	"time"
)

// CommonsController 需要手动注册
type CommonsController struct {
	BaseController
	SysUserService *service.SysUserService
}

// RegisterRouter 注册路由
func (controller *CommonsController) RegisterRouter(engine *gin.Engine) {
	engine.POST("/login", controller.Login)
	engine.POST("/register", controller.Register)
	engine.GET("/captcha", controller.GetVerifyCode)
	engine.GET("/logout", controller.Logout)
}

// Login 用户登录
// @Summary Login  用户登录
// @Tags 公共模块
// @Produce json
// @Param sysSysUser body  dto.LoginSysUserDto true "用户登录信息"
// @Success 200 {object} Result "成功"
// @Router /login [post]
func (controller *CommonsController) Login(ctx *gin.Context) {
	var loginSysUserDto dto.LoginSysUserDto
	err := ctx.ShouldBind(&loginSysUserDto)
	controller.HandleError(err, constant.PARAMS_ERROR)

	//验证验证码是否正确
	if !verifyCode.VerifyVerifyCode(loginSysUserDto.VerifyUuid, loginSysUserDto.VerifyCode) {
		controller.FailResult(ctx, "验证码错误！")
		return
	}

	sysUser := controller.SysUserService.QuerySysUserByUsername(loginSysUserDto.Username)
	//密码不正确
	if sysUser.Id == nil || !bcrypt.PasswordCompare(*sysUser.Password, loginSysUserDto.Password) {
		controller.FailResult(ctx, "用户名或密码错误！")
		return
	}

	sysUser.Password = nil
	token := jwt.GeneratorToken(fmt.Sprint(*sysUser.Id))

	//只允许单一设备登录
	client := container.GetBeanFromContainer("redis.Client").(*redis.Client)
	userJson, _ := json.Marshal(&sysUser)
	//存储用户信息，为什么用户信息只存一个小时，是因为减轻redis的压力
	client.Set(ctx, fmt.Sprintf("%s:%d", constant.REDIS_KEY_SYS_LOGINUSER, *sysUser.Id), string(userJson), time.Hour*24*7)
	//每个用户在Redis中都有一个map值管理他的token列表
	client.HSet(ctx, constant.REDIS_KEY_SYS_LOGINUSERID_TOKEN+fmt.Sprint(*sysUser.Id), token, true)
	menuPermissions := client.HGet(ctx, constant.REDIS_KEY_SYS_ROLE_MENUS_PERMISSSIONS, fmt.Sprintf("%d", *sysUser.Role)).Val()
	// 返回JWT tok,en
	controller.SuccessResult(ctx, gin.H{
		"sysUser":   sysUser,
		"token":     token,
		"authority": menuPermissions,
	})
}

// Register 用户注册
// @Summary Register 用户注册
// @Tags 公共模块
// @Produce json
// @Param sysSysUserDto body dto.RegisterSysUserDto true "用户登录信息"
// @Success 200 {object} Result "成功"
// @Router /register [post]
func (controller *CommonsController) Register(ctx *gin.Context) {
	var registerSysUserDto dto.RegisterSysUserDto
	err := ctx.ShouldBind(&registerSysUserDto)
	controller.HandleError(err, constant.PARAMS_ERROR)

	//验证验证码是否正确
	if !verifyCode.VerifyVerifyCode(registerSysUserDto.VerifyUuid, registerSysUserDto.VerifyCode) {
		controller.FailResult(ctx, "验证码错误！")
		return
	}

	//负值到系统用户对象
	var sysUser = models.SysUser{
		Username: &registerSysUserDto.Username,
		Password: &registerSysUserDto.Password,
		NickName: &registerSysUserDto.NickName,
		Age:      &registerSysUserDto.Age,
		Phone:    &registerSysUserDto.Phone,
		Role:     new(int),
	}
	//设置角色为普通用户
	*sysUser.Role = 2

	//添加用户
	controller.SysUserService.AddSysUser(&sysUser)

	//注册成功
	controller.CustomResult(ctx, http.StatusOK, "注册用户成功", nil)
}

// Logout 用户登出
// @Summary Logout 用户登出
// @Tags 公共模块
// @Produce json
// @Success 200 {object} Result "成功"
// @Router /logout [get]
func (controller *CommonsController) Logout(ctx *gin.Context) {
	userId, exists := ctx.Get(constant.REQUEST_CONTEXT_LOGIN_USER_ID)
	if !exists {
		controller.FailResult(ctx, "未登录！")
		return
	}
	client := container.GetBeanFromContainer("redis.Client").(*redis.Client)
	client.HDel(ctx, fmt.Sprintf("%s%v", constant.REDIS_KEY_SYS_LOGINUSERID_TOKEN, userId), ctx.GetHeader("token"))
	controller.SuccessResult(ctx, "退出登录成功")
}

// GetVerifyCode 获取验证码
// @Summary GetVerifyCode 获取验证码
// @Tags 公共模块
// @Success 200 {object} Result "成功"
// @Router /captcha [post]
func (controller *CommonsController) GetVerifyCode(ctx *gin.Context) {
	id, base64Image := verifyCode.GeneratorVerifyCodeImage()

	controller.SuccessResult(ctx, gin.H{
		"verifyUUID":  id,
		"verifyImage": base64Image,
	})
}
